Spring MVC 之 @RequestMapping(1)

版权声明:本文为博主原创文章,转载请注明出处,谢谢!

版权声明:本文为博主原创文章,转载请注明出处:http://blog.jerkybible.com/2015/06/02/Spring MVC 之 RequestMapping(1)/

访问原文「Spring MVC 之 @RequestMapping(1)

一、从@AutoWaired开始

在@AutoWaired中有下面的一段代码,其中populateBean负责属性的加载。而initializeBean完成属性属性加载后的自定义操作。
1
2
3
4
5
6
7
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}

来看一下initializeBean的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
//这里检测当前Bean是否实现一些列Aware接口,并调用相关方法。
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用初始化方法的方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

接着看下invokeInitMethods方法的实现。在的解析中,我们了解到Spring会默认为我们注册RequestMappingHandlerMapping等Bean定义。而RequestMappingHandlerMapping 实现了InitializingBean接口,因此,在初始化并装配该Bean实例时,执行到上述代码是,便会执行他的afterPropertySet方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
//判断是否是InitializingBean的实例
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}

接着看一下RequestMappingHandlerMapping的afterPropertySet方法。会进入AbstractHandlerMethodMapping中的initHandlerMethods方法,如下。该方法扫描ApplicationContext中的beans,检测并注册处理器方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//扫描所有注册的Bean
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
//遍历这些Bean,依次判断是否是处理器,并检测其HandlerMethod
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
isHandler(getApplicationContext().getType(beanName))){
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}

二、detectHandlerMethods

展开上一节中的detectHandlerMethods。一共分为以下步骤。
1)遍历Handler中的所有方法,找出其中被@RequestMapping注解标记的方法。
2)然后遍历这些方法,生成RequestMappingInfo实例。
3)将RequestMappingInfo实例以及处理器方法注册到缓存中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType =
(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
// Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances
final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
@Override
public boolean matches(Method method) {
//根据方法上的@RequestMapping来创建RequestMappingInfo实例。
T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
}
else {
return false;
}
}
});
//注册请求映射
for (Method method : methods) {
registerHandlerMethod(handler, method, mappings.get(method));
}
}

展开getMappingForMethod。这一步根据注解生成RequestMappingInfo。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = null;
RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
if (methodAnnotation != null) {
RequestCondition<?> methodCondition = getCustomMethodCondition(method);
info = createRequestMappingInfo(methodAnnotation, methodCondition);
RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
if (typeAnnotation != null) {
RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
}
}
return info;
}

展开createRequestMappingInfo。
其中涉及到了几个类,我们大致了解下含义:
PatternRequestCondition 它其实就是URL模式的封装,它包含了一个URL模式的Set集合。其实就是@RequestMapping注解中的value值得封装;
RequestMethodRequestCondition 它是@RequestMapping 注解中method属性的封装;
ParamsRequestCondition 它是@RequestMapping注解中params属性的封装;
等等,依次类推。因此RequestMappingInfo其实就是对@RquestMapping 的封装。
生成了RequestMappingInfo 对每一个元素都进行combine操作,不再详细讲解。

1
2
3
4
5
6
7
8
9
10
11
12
13
protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
return new RequestMappingInfo(
annotation.name(),
new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
new RequestMethodsRequestCondition(annotation.method()),
new ParamsRequestCondition(annotation.params()),
new HeadersRequestCondition(annotation.headers()),
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager),
customCondition);
}

再回到本节第一个方法中的registerHandlerMethod方法。这个方法就是生成新的HandlerMethod实例,然后加入handlerMethods中,接着生成mapping中所有的url放入urlMap中。当请求到达时,去urlMap中需找匹配的url,以及获取对应mapping实例,然后去handlerMethods中获取匹配HandlerMethod实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
//根据新的处理器实例,方法实例,RequestMappingInfo来生成新的HandlerMethod实例
//从缓存中查看是否有存在的HandlerMethod实例,如果有并且不相等则抛出异常
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +
"' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +
oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
}
//handlerMethods 是一个Map键是RequestMappingInfo对象,值是HandlerMethod实例
//因此一个HandlerMethod实例可能处理多个mapping,而一个mapping实例只能由一个method处理
this.handlerMethods.put(mapping, newHandlerMethod);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
}
//这里获取mapping实例中的所有url。
Set<String> patterns = getMappingPathPatterns(mapping);
//urlMap也是Map,键是url 模式,值是RequestMappingInfo实例
//因此一个mapping实例可能对应多个pattern,但是一个pattern只能对应一个mapping实例
for (String pattern : patterns) {
if (!getPathMatcher().isPattern(pattern)) {
this.urlMap.add(pattern, mapping);
}
}
if (this.namingStrategy != null) {
String name = this.namingStrategy.getName(newHandlerMethod, mapping);
updateNameMap(name, newHandlerMethod);
}
}

接着会分析Spring怎样处理客户发来的请求。

Jerky Lu wechat
欢迎加入微信公众号